﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Web.Mvc;

using System.ComponentModel;
using MvcEngine.Core.Validation;
using MvcEngine.Core.Localization;
using System.Text.RegularExpressions;

namespace MvcEngine.Core.Helpers
{
    public class ValidationHelper : IValidationHelper
    {
        public static IValidationHelper Current
        {
            get { return IoC.Resolve<IValidationHelper>(); }
        }

        public IEnumerable<BrokenRule> GetErrors<TInterface>(object instance)
        {
            return GetErrors<TInterface>(instance, (string[])null);
        }

        public IEnumerable<BrokenRule> GetErrors<TInterface>(object instance, string[] excludeProperties)
        {
            Type interfaceType = typeof(TInterface);

            List<BrokenRule> errors = new List<BrokenRule>();

            foreach (var item in interfaceType.GetProperties())
            {
                if (excludeProperties != null && excludeProperties.Contains(item.Name))
                    continue;
                object[] attributes = item.GetCustomAttributes(typeof(FieldValidatorAttribute), false);
                foreach (FieldValidatorAttribute attribute in attributes)
                {
                    if (!attribute.IsValid(item.GetValue(instance, null)))
                    {
                        errors.Add(new BrokenRule(item.Name, attribute.ErrorMessage, instance));
                    }
                }
            }
            return errors;
        }

        public IEnumerable<BrokenRule> GetErrors<TInterface>(object instance, string propertyName)
        {
            Type interfaceType = typeof(TInterface);

            List<BrokenRule> errors = new List<BrokenRule>();

            PropertyInfo item = interfaceType.GetProperties().SingleOrDefault(p => p.Name == propertyName);

            Guard.ThrowIfNull(item, "Property " + propertyName + " was not found in object");

            object[] attributes = item.GetCustomAttributes(typeof(FieldValidatorAttribute), false);
            foreach (FieldValidatorAttribute attribute in attributes)
            {
                if (!attribute.IsValid(item.GetValue(instance, null)))
                {
                    errors.Add(new BrokenRule(item.Name, attribute.ErrorMessage, instance));
                }
            }

            return errors;
        }

        public void Validate<TInterface>(object instance)
        {
            IEnumerable<BrokenRule> errors = GetErrors<TInterface>(instance);
            if (errors.Count() > 0)
                throw new ValidationException(errors);
        }

        public void Validate<TInterface>(object instance, string propertyToValidate)
        {
            IEnumerable<BrokenRule> errors = GetErrors<TInterface>(instance, propertyToValidate);
            if (errors.Count() > 0)
                throw new ValidationException(errors);
        }

        public void UpdateModelState(ValidationException exception, ModelStateDictionary modelState)
        {
            foreach (BrokenRule rule in exception.BrokenRules)
            {
                modelState.AddModelError(rule.PropertyName, rule.ErrorMessage);
            }
        }

        public void UpdateModelState(IEnumerable<BrokenRule> brokenRules, ModelStateDictionary modelState)
        {
            foreach (BrokenRule rule in brokenRules)
            {
                modelState.AddModelError(rule.PropertyName, rule.ErrorMessage);
            }
        }

        public bool ValidateEmail(string email)
        {
            string expression = ResourceReader.Current.GetString("$EmailRegexExpression", true);
            Regex regex = new Regex(expression);
            return regex.IsMatch(email);
        }
    }
}
